Skip to main content
Duet’s SSH server is built on Charm’s Wish framework, which provides a composable middleware system for building SSH applications.

Server Structure

The server is defined in /internal/server/server.go:

Initialization

The server is created with connection details and a room manager instance:
Key Points:
  • Default address is :2222
  • Host key path defaults to .ssh/id_ed25519 (auto-generated if missing)
  • AI client is optional (only created if worker URL provided)
  • Room manager is shared across all connections

Wish Server Configuration

The server is configured with Wish middleware:

Middleware Stack

Duet uses two middleware layers:
  1. Bubble Tea Middleware: Handles TUI creation for each SSH session
  2. Logging Middleware: Logs connection events and errors
Middleware executes in order from top to bottom. The Bubble Tea middleware is the primary handler.

Bubble Tea Handler

The teaHandler function is called for each new SSH connection:

Session Information

  • Username: Extracted from SSH session (defaults to “guest”)
  • Renderer: Created per-session for style rendering
  • PTY Info: Terminal type and color profile detection
  • Alt Screen: Uses alternate screen buffer (terminal state is preserved on exit)

Color Profile Detection

The handler detects terminal capabilities:
This ensures proper color rendering for clients with different terminal emulators.

Lifecycle Management

Graceful Shutdown

The server listens for interrupt signals and shuts down gracefully:
Shutdown Process:
  1. Wait for SIGINT or SIGTERM signal
  2. Log shutdown message
  3. Create 10-second timeout context
  4. Call srv.Shutdown() to close active connections
  5. Return any shutdown errors

Connection Lifecycle

Authentication

Duet uses public key authentication via the host key:

Host Key Generation

Wish automatically generates an Ed25519 host key if the file doesn’t exist:
The key is stored at the specified path and reused for subsequent starts.

Per-Session Isolation

Each SSH session gets:
  • Unique Bubble Tea model instance (ui.New(...))
  • Unique client ID (uuid.New().String())
  • Separate event channel for room notifications
  • Independent terminal subscription when joining a room
Shared across sessions:
  • Room Manager (singleton)
  • Terminal instances (one per room, shared by all clients in that room)
  • AI Client (if configured)

Configuration Options

Command-line flags in main.go:

Example Usage

Error Handling

The server handles errors at multiple levels:
Client-level errors are handled in the Bubble Tea model’s Update method via ErrorMsg messages.

Security Considerations

  • Host Key: Securely store the host key file with appropriate permissions (0600)
  • No Password Auth: Only public key authentication is supported
  • Workspace Isolation: Each room uses a separate workspace directory
  • PTY Restrictions: Terminal processes run in isolated directories
For production deployments, consider:
  • Rate limiting connections
  • Authentication via SSH keys
  • Network-level access controls
  • Monitoring and logging